package com.datagateway.component;

import com.datagateway.model.ProcessedData;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;

/**
 * 数据质量检查器
 * 负责数据验证、清洗、去重等质量检查工作
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@Component
public class DataQualityChecker {

    private static final Logger logger = LoggerFactory.getLogger(DataQualityChecker.class);

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private AlertManager alertManager;

    /**
     * 数据质量检查结果
     */
    public enum QualityResult {
        PASS,           // 通过
        WARN,           // 警告
        FAIL,           // 失败
        SKIP            // 跳过
    }

    /**
     * 数据质量规则类型
     */
    public enum RuleType {
        REQUIRED_FIELD,     // 必填字段检查
        DATA_TYPE,          // 数据类型检查
        VALUE_RANGE,        // 值范围检查
        FORMAT_VALIDATION,  // 格式验证
        DUPLICATE_CHECK,    // 重复检查
        BUSINESS_RULE       // 业务规则检查
    }

    /**
     * 质量检查统计
     */
    private final AtomicLong totalChecked = new AtomicLong(0);
    private final AtomicLong passedCount = new AtomicLong(0);
    private final AtomicLong warnedCount = new AtomicLong(0);
    private final AtomicLong failedCount = new AtomicLong(0);
    private final AtomicLong skippedCount = new AtomicLong(0);

    /**
     * 重复数据缓存（用于去重）
     */
    private final Map<String, LocalDateTime> duplicateCache = new ConcurrentHashMap<>();

    /**
     * 数据质量规则配置
     */
    private final Map<String, QualityRule> qualityRules = new ConcurrentHashMap<>();

    /**
     * 初始化默认质量规则
     */
    public void initializeDefaultRules() {
        // 必填字段规则
        addQualityRule("required_id", new QualityRule(
            RuleType.REQUIRED_FIELD, "id", "数据ID不能为空", true
        ));
        
        addQualityRule("required_timestamp", new QualityRule(
            RuleType.REQUIRED_FIELD, "timestamp", "时间戳不能为空", true
        ));

        // 数据类型规则
        addQualityRule("id_format", new QualityRule(
            RuleType.FORMAT_VALIDATION, "id", "ID格式验证", false
        ));

        // 值范围规则
        addQualityRule("timestamp_range", new QualityRule(
            RuleType.VALUE_RANGE, "timestamp", "时间戳范围检查", false
        ));

        // 重复检查规则
        addQualityRule("duplicate_check", new QualityRule(
            RuleType.DUPLICATE_CHECK, "id", "重复数据检查", true
        ));

        logger.info("默认数据质量规则初始化完成，规则数量: {}", qualityRules.size());
    }

    /**
     * 检查数据质量
     * 
     * @param data 要检查的数据
     * @return 质量检查结果
     */
    public QualityCheckResult checkDataQuality(ProcessedData data) {
        totalChecked.incrementAndGet();
        
        List<QualityIssue> issues = new ArrayList<>();
        QualityResult overallResult = QualityResult.PASS;

        try {
            // 执行各种质量检查
            checkRequiredFields(data, issues);
            checkDataTypes(data, issues);
            checkValueRanges(data, issues);
            checkFormats(data, issues);
            checkDuplicates(data, issues);
            checkBusinessRules(data, issues);

            // 确定整体结果
            overallResult = determineOverallResult(issues);

            // 更新统计
            updateStatistics(overallResult);

            // 如果质量检查失败，发送告警
            if (overallResult == QualityResult.FAIL) {
                alertManager.sendDataProcessingAlert(
                    "数据质量检查失败: " + data.getId(), 
                    data.getId()
                );
            }

        } catch (Exception e) {
            logger.error("数据质量检查异常: dataId={}", data.getId(), e);
            issues.add(new QualityIssue("SYSTEM_ERROR", "质量检查系统异常", e.getMessage()));
            overallResult = QualityResult.FAIL;
            failedCount.incrementAndGet();
        }

        return new QualityCheckResult(data.getId(), overallResult, issues, LocalDateTime.now());
    }

    /**
     * 检查必填字段
     * 
     * @param data 数据
     * @param issues 问题列表
     */
    private void checkRequiredFields(ProcessedData data, List<QualityIssue> issues) {
        // 检查数据ID
        if (data.getId() == null || data.getId().trim().isEmpty()) {
            issues.add(new QualityIssue("REQUIRED_ID", "数据ID不能为空", "id字段缺失或为空"));
        }

        // 检查原始数据
        if (data.getOriginalData() == null || data.getOriginalData().trim().isEmpty()) {
            issues.add(new QualityIssue("REQUIRED_ORIGINAL_DATA", "原始数据不能为空", "originalData字段缺失或为空"));
        }

        // 检查转换后数据
        if (data.getTransformedData() == null || data.getTransformedData().isEmpty()) {
            issues.add(new QualityIssue("REQUIRED_TRANSFORMED_DATA", "转换后数据不能为空", "transformedData字段缺失或为空"));
        }
    }

    /**
     * 检查数据类型
     * 
     * @param data 数据
     * @param issues 问题列表
     */
    private void checkDataTypes(ProcessedData data, List<QualityIssue> issues) {
        try {
            if (data.getTransformedData() != null) {
                // 检查时间戳字段
                Object timestamp = data.getTransformedData().get("timestamp");
                if (timestamp != null) {
                    if (!(timestamp instanceof Number) && !(timestamp instanceof String)) {
                        issues.add(new QualityIssue("INVALID_TIMESTAMP_TYPE", "时间戳类型错误", 
                            "timestamp字段类型应为Number或String"));
                    }
                }

                // 检查数值字段
                Object value = data.getTransformedData().get("value");
                if (value != null && !(value instanceof Number)) {
                    issues.add(new QualityIssue("INVALID_VALUE_TYPE", "数值类型错误", 
                        "value字段类型应为Number"));
                }
            }
        } catch (Exception e) {
            issues.add(new QualityIssue("DATA_TYPE_CHECK_ERROR", "数据类型检查异常", e.getMessage()));
        }
    }

    /**
     * 检查值范围
     * 
     * @param data 数据
     * @param issues 问题列表
     */
    private void checkValueRanges(ProcessedData data, List<QualityIssue> issues) {
        try {
            if (data.getTransformedData() != null) {
                // 检查时间戳范围
                Object timestamp = data.getTransformedData().get("timestamp");
                if (timestamp instanceof Number) {
                    long ts = ((Number) timestamp).longValue();
                    long now = System.currentTimeMillis();
                    long oneYearAgo = now - 365L * 24 * 60 * 60 * 1000;
                    long oneYearLater = now + 365L * 24 * 60 * 60 * 1000;
                    
                    if (ts < oneYearAgo || ts > oneYearLater) {
                        issues.add(new QualityIssue("TIMESTAMP_OUT_OF_RANGE", "时间戳超出合理范围", 
                            "时间戳应在过去一年到未来一年之间"));
                    }
                }

                // 检查数值范围
                Object value = data.getTransformedData().get("value");
                if (value instanceof Number) {
                    double val = ((Number) value).doubleValue();
                    if (val < -1000000 || val > 1000000) {
                        issues.add(new QualityIssue("VALUE_OUT_OF_RANGE", "数值超出合理范围", 
                            "数值应在-1000000到1000000之间"));
                    }
                }
            }
        } catch (Exception e) {
            issues.add(new QualityIssue("VALUE_RANGE_CHECK_ERROR", "值范围检查异常", e.getMessage()));
        }
    }

    /**
     * 检查格式
     * 
     * @param data 数据
     * @param issues 问题列表
     */
    private void checkFormats(ProcessedData data, List<QualityIssue> issues) {
        try {
            // 检查ID格式
            if (data.getId() != null) {
                if (!Pattern.matches("^[a-zA-Z0-9_-]+$", data.getId())) {
                    issues.add(new QualityIssue("INVALID_ID_FORMAT", "ID格式错误", 
                        "ID只能包含字母、数字、下划线和连字符"));
                }
            }

            // 检查JSON格式
            if (data.getOriginalData() != null) {
                try {
                    objectMapper.readTree(data.getOriginalData());
                } catch (Exception e) {
                    issues.add(new QualityIssue("INVALID_JSON_FORMAT", "JSON格式错误", e.getMessage()));
                }
            }

            // 检查邮箱格式
            if (data.getTransformedData() != null) {
                Object email = data.getTransformedData().get("email");
                if (email instanceof String) {
                    String emailStr = (String) email;
                    if (!emailStr.isEmpty() && !Pattern.matches("^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$", emailStr)) {
                        issues.add(new QualityIssue("INVALID_EMAIL_FORMAT", "邮箱格式错误", 
                            "邮箱格式不正确: " + emailStr));
                    }
                }
            }
        } catch (Exception e) {
            issues.add(new QualityIssue("FORMAT_CHECK_ERROR", "格式检查异常", e.getMessage()));
        }
    }

    /**
     * 检查重复数据
     * 
     * @param data 数据
     * @param issues 问题列表
     */
    private void checkDuplicates(ProcessedData data, List<QualityIssue> issues) {
        try {
            if (data.getId() != null) {
                String dataKey = data.getId();
                LocalDateTime now = LocalDateTime.now();
                
                // 检查是否在缓存中存在
                LocalDateTime lastSeen = duplicateCache.get(dataKey);
                if (lastSeen != null) {
                    // 如果在5分钟内重复出现，认为是重复数据
                    if (lastSeen.isAfter(now.minusMinutes(5))) {
                        issues.add(new QualityIssue("DUPLICATE_DATA", "重复数据", 
                            "数据ID在5分钟内重复出现: " + dataKey));
                    }
                }
                
                // 更新缓存
                duplicateCache.put(dataKey, now);
                
                // 清理过期缓存（超过1小时的数据）
                cleanupExpiredCache(now);
            }
        } catch (Exception e) {
            issues.add(new QualityIssue("DUPLICATE_CHECK_ERROR", "重复检查异常", e.getMessage()));
        }
    }

    /**
     * 检查业务规则
     * 
     * @param data 数据
     * @param issues 问题列表
     */
    private void checkBusinessRules(ProcessedData data, List<QualityIssue> issues) {
        try {
            if (data.getTransformedData() != null) {
                // 示例业务规则：用户ID和邮箱必须匹配
                Object userId = data.getTransformedData().get("user_id");
                Object email = data.getTransformedData().get("email");
                
                if (userId != null && email != null) {
                    String emailStr = email.toString();
                    if (emailStr.contains("@") && !emailStr.startsWith(userId.toString())) {
                        // 这里可以添加更复杂的业务规则验证
                        // 暂时跳过这个检查
                    }
                }

                // 示例业务规则：金额不能为负数
                Object amount = data.getTransformedData().get("amount");
                if (amount instanceof Number) {
                    double amt = ((Number) amount).doubleValue();
                    if (amt < 0) {
                        issues.add(new QualityIssue("NEGATIVE_AMOUNT", "金额不能为负数", 
                            "业务规则：金额不能为负数"));
                    }
                }
            }
        } catch (Exception e) {
            issues.add(new QualityIssue("BUSINESS_RULE_CHECK_ERROR", "业务规则检查异常", e.getMessage()));
        }
    }

    /**
     * 确定整体结果
     * 
     * @param issues 问题列表
     * @return 整体结果
     */
    private QualityResult determineOverallResult(List<QualityIssue> issues) {
        if (issues.isEmpty()) {
            return QualityResult.PASS;
        }

        // 检查是否有严重问题
        for (QualityIssue issue : issues) {
            if (issue.getSeverity().equals("CRITICAL") || issue.getSeverity().equals("ERROR")) {
                return QualityResult.FAIL;
            }
        }

        // 检查是否有警告
        for (QualityIssue issue : issues) {
            if (issue.getSeverity().equals("WARN")) {
                return QualityResult.WARN;
            }
        }

        return QualityResult.PASS;
    }

    /**
     * 更新统计信息
     * 
     * @param result 检查结果
     */
    private void updateStatistics(QualityResult result) {
        switch (result) {
            case PASS:
                passedCount.incrementAndGet();
                break;
            case WARN:
                warnedCount.incrementAndGet();
                break;
            case FAIL:
                failedCount.incrementAndGet();
                break;
            case SKIP:
                skippedCount.incrementAndGet();
                break;
        }
    }

    /**
     * 清理过期缓存
     * 
     * @param now 当前时间
     */
    private void cleanupExpiredCache(LocalDateTime now) {
        LocalDateTime cutoff = now.minusHours(1);
        duplicateCache.entrySet().removeIf(entry -> entry.getValue().isBefore(cutoff));
    }

    /**
     * 添加质量规则
     * 
     * @param ruleId 规则ID
     * @param rule 质量规则
     */
    public void addQualityRule(String ruleId, QualityRule rule) {
        qualityRules.put(ruleId, rule);
    }

    /**
     * 获取质量检查统计
     * 
     * @return 质量检查统计
     */
    public QualityStatistics getQualityStatistics() {
        return new QualityStatistics(
            totalChecked.get(),
            passedCount.get(),
            warnedCount.get(),
            failedCount.get(),
            skippedCount.get()
        );
    }

    /**
     * 质量规则类
     */
    public static class QualityRule {
        private final RuleType type;
        private final String field;
        private final String description;
        private final boolean required;

        public QualityRule(RuleType type, String field, String description, boolean required) {
            this.type = type;
            this.field = field;
            this.description = description;
            this.required = required;
        }

        // Getter方法
        public RuleType getType() { return type; }
        public String getField() { return field; }
        public String getDescription() { return description; }
        public boolean isRequired() { return required; }
    }

    /**
     * 质量检查结果类
     */
    public static class QualityCheckResult {
        private final String dataId;
        private final QualityResult result;
        private final List<QualityIssue> issues;
        private final LocalDateTime checkTime;

        public QualityCheckResult(String dataId, QualityResult result, List<QualityIssue> issues, LocalDateTime checkTime) {
            this.dataId = dataId;
            this.result = result;
            this.issues = issues;
            this.checkTime = checkTime;
        }

        // Getter方法
        public String getDataId() { return dataId; }
        public QualityResult getResult() { return result; }
        public List<QualityIssue> getIssues() { return issues; }
        public LocalDateTime getCheckTime() { return checkTime; }
    }

    /**
     * 质量问题类
     */
    public static class QualityIssue {
        private final String code;
        private final String message;
        private final String details;
        private final String severity;

        public QualityIssue(String code, String message, String details) {
            this.code = code;
            this.message = message;
            this.details = details;
            this.severity = determineSeverity(code);
        }

        private String determineSeverity(String code) {
            if (code.contains("REQUIRED") || code.contains("CRITICAL")) {
                return "CRITICAL";
            } else if (code.contains("INVALID") || code.contains("ERROR")) {
                return "ERROR";
            } else if (code.contains("WARN")) {
                return "WARN";
            } else {
                return "INFO";
            }
        }

        // Getter方法
        public String getCode() { return code; }
        public String getMessage() { return message; }
        public String getDetails() { return details; }
        public String getSeverity() { return severity; }
    }

    /**
     * 质量统计信息类
     */
    public static class QualityStatistics {
        private final long totalChecked;
        private final long passedCount;
        private final long warnedCount;
        private final long failedCount;
        private final long skippedCount;

        public QualityStatistics(long totalChecked, long passedCount, long warnedCount, long failedCount, long skippedCount) {
            this.totalChecked = totalChecked;
            this.passedCount = passedCount;
            this.warnedCount = warnedCount;
            this.failedCount = failedCount;
            this.skippedCount = skippedCount;
        }

        // Getter方法
        public long getTotalChecked() { return totalChecked; }
        public long getPassedCount() { return passedCount; }
        public long getWarnedCount() { return warnedCount; }
        public long getFailedCount() { return failedCount; }
        public long getSkippedCount() { return skippedCount; }
        public double getPassRate() { 
            return totalChecked > 0 ? (double) passedCount / totalChecked * 100 : 0; 
        }
        public double getFailureRate() { 
            return totalChecked > 0 ? (double) failedCount / totalChecked * 100 : 0; 
        }

        @Override
        public String toString() {
            return String.format("QualityStatistics{totalChecked=%d, passedCount=%d, " +
                               "warnedCount=%d, failedCount=%d, skippedCount=%d, " +
                               "passRate=%.2f%%, failureRate=%.2f%%}",
                               totalChecked, passedCount, warnedCount, failedCount, skippedCount, 
                               getPassRate(), getFailureRate());
        }
    }
}
